package uhasselt.ontologyplugin;

import java.io.StringReader;
import javax.xml.transform.stream.StreamSource;
import java.lang.UnsupportedOperationException;


import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.DocumentBuilder;
import net.sf.saxon.s9api.XdmNode;
import net.sf.saxon.s9api.XQueryCompiler;
import net.sf.saxon.s9api.XQueryExecutable;
import net.sf.saxon.s9api.XQueryEvaluator;
import net.sf.saxon.s9api.QName;


import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
import javax.xml.ws.soap.SOAPFaultException;
import javax.xml.ws.WebServiceClient;
import org.fao.webservices.agrovocws.ACSWWebServiceService;
import org.fao.webservices.agrovocws.ACSWWebService;
@WebServiceClient(name = "ACSWWebServiceService", 
                  wsdlLocation = "classpath:ACSWWebService.xml",
                  targetNamespace = "http://www.fao.org/webservices/AgrovocWS")
class FaoReader extends OntologyReader {

	private static final String _format = "SKOS"; 
	
    ACSWWebService _port = null;
	private String _ontology = null;
	
	private static final javax.xml.namespace.QName SERVICE_NAME = new javax.xml.namespace.QName("http://www.fao.org/webservices/AgrovocWS", "ACSWWebServiceService");

	
	/**
	 * @param uri The uri of the keyword
     * @param searchTerm The relation name
     * @return The relations of the keyword, e.g. the broader terms or the narrower terms, this is returned in the format of the ontology
	 */
	public XdmNode search(String searchTerm,SearchMode mode,String lang) throws UnsupportedOperationException{
		try {
			return 	_transformer.transform(_port.getTermExpansion(_ontology,searchTerm,_format,getSearchMode(mode),lang));
		}catch (SOAPFaultException e ){
			return _transformer.transform("");
		}
	}
	
	/**
	 * @param uri Concept URI 
	 * @param relName The name of the relation you want to retrieve
	 * @return The relation (relName) of the given concept
	 * TODO: Misschien precompiled xquery gebruiken in de plaats
	 */
	public XdmNode getRelations(String uri,RelationName relName,String lang) throws UnsupportedOperationException{
	
		try {
			// Required xquery init
			XdmNode result= getConcept(uri,lang);
			Processor processor = ToSkosTransformer.getProcessorInstance();
			DocumentBuilder documentBuilder = processor.newDocumentBuilder();
			XQueryCompiler xQueryCompiler = processor.newXQueryCompiler();
			
			// The actual query
			XQueryExecutable xQueryExecutable = xQueryCompiler.compile(
			"declare namespace skos = \"http://www.w3.org/2004/02/skos/core#\";"+
			"declare namespace rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\";"+
			"declare variable $queryResult external; " +
			"<rdf:RDF>{$queryResult//skos:"+ getRelationName(relName) + "/skos:Concept}" +
			"</rdf:RDF>");
			
		    // Load the query
			XQueryEvaluator xQueryEvaluator = xQueryExecutable.load();
			
			// Load the input document

			
			// Insert the input document in the query 
			QName name = new QName("queryResult");
			xQueryEvaluator.setExternalVariable(name, result);
			RemoveNameSpaces s = new RemoveNameSpaces();
			return RemoveNameSpaces.getInstance().transform((XdmNode)xQueryEvaluator.evaluateSingle());
		
		}catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}
	
	
	public XdmNode getTopLevelTerms(String lang) throws UnsupportedOperationException{
		throw new UnsupportedOperationException();
	}
	
	/**
	 * @param uri The `URI' of the concept
     * @return The concept with the given uri
	 */
	public XdmNode getConcept(String uri,String lang){
		try{
			return _transformer.transform(_port.getConceptByURI(_ontology,uri,_format));
		}catch (SOAPFaultException e ){
			return _transformer.transform("");
		}
	}
	
	/**
     * @param name RelationName
	 * @retuns seralized name for VocBench `querying'
     */	
	private String getRelationName(OntologyReader.RelationName name)throws UnsupportedOperationException{
		switch (name){
			case BROADER:
				return "broader";
			case NARROWER:
				return "narrower";
			case RELATED:
				return "related";
			default:
			throw new UnsupportedOperationException("Cannot call this function with the given parameters");
		}
	}
	/**
	 * @param mode Search Mode
	 * @return mode serialized for VocBench `querying'
	 */
	private String getSearchMode(OntologyReader.SearchMode mode) throws UnsupportedOperationException{
		switch (mode){
			case CONTAINS:
				return "contains";
			case EXACT:
				return "exact match";
			case STARTSWITH:
				return "starts with";
			case ENDSWITH:
				return "ends with";
			default:
				throw new UnsupportedOperationException("Cannot call this function with the given parameters");
		}
	}	
	

	/**
	 * 
	 */
	public void initialise(PropertyReader reader, String thesaurus){
		_ontology =reader.getValue(thesaurus +".ontologyname");
			try {

			URL	wsdlURL = FaoReader.class.getClassLoader().getResource("ACSWWebService.xml");

			// Load the service
			ACSWWebServiceService ss = new ACSWWebServiceService(wsdlURL, SERVICE_NAME);
			// Load the port to query
			_port = ss.getACSWWebService();  
		} catch (Exception e){
			e.printStackTrace();
		}
		
	}
}
